/******************************************************************************

    Copyright (C) 2006 - 2010 Alessio Stalla (alessiostalla@gmail.com)

    This file is part of PrettyProlog.

    PrettyProlog is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    PrettyProlog is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PrettyProlog; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    See the file COPYING for further details.

 *****************************************************************************/

package prettyprolog.engine.syspreds;

import java.util.List;

import prettyprolog.datatypes.Substitution;
import prettyprolog.datatypes.Term;
import prettyprolog.engine.Engine;

/** The superclass of every system predicate. */
public abstract class SystemPredicate {
	
	protected int requiredArgumentsCount = 0;
	
	protected SystemPredicate() {}
	
	protected SystemPredicate(int requiredArgumentsCount) {
		this.requiredArgumentsCount = requiredArgumentsCount;
	}
	
	/**
	 * This method is called by the PrettyProlog engine to resolve the effect of
	 * this system predicate.
	 * 
	 * @return a SyspredEffect with info used by the Engine to continue solving
	 *         after this call.
	 * @throws SyspredException
	 *             if an exception occurs while calling this syspred.
	 */
	protected abstract SyspredEffect doCall(Engine en, Substitution subst, List<Term> args) throws SyspredException;
	
	public SyspredEffect call(Engine en, Substitution subst, List<Term> args) throws SyspredException {
		if(!(args.size() == getRequiredArgumentsCount())) {
			throw new WrongArgumentNumberException(this, requiredArgumentsCount, args.size());
		}
		return doCall(en, subst, args);
	}
	
	/**
	 * @return true if on backtracking the engine will re-execute this system
	 *         predicate, false otherwise.
	 */
	public abstract boolean isBacktrackable();

	public String toString() {
		return "System predicate";
	}
	
	public int getRequiredArgumentsCount() {
		return requiredArgumentsCount;
	} 
	
	protected SystemPredicate requiredArgumentsCount(int requiredArgumentsCount) {
		this.requiredArgumentsCount = requiredArgumentsCount;
		return this;
	}
}